package byx.container.annotation.extension.impl;

import byx.container.annotation.extension.core.AnnotationMetadata;
import byx.container.annotation.extension.core.ParameterHandler;
import byx.container.annotation.extension.core.ParameterInfo;
import byx.container.core.Container;
import byx.container.core.ObjectFactory;
import byx.container.core.exception.ContainerException;

import java.lang.annotation.Annotation;
import java.lang.reflect.Executable;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

/**
 * 方法参数解析器
 * 用于将方法的每一个参数解析成ObjectFactory
 *
 * @author byx
 */
public class ParameterResolver {
    private final Container container;
    private final List<ParameterHandler> parameterHandlers;

    public ParameterResolver(Container container, List<ParameterHandler> parameterHandlers) {
        this.container = container;
        this.parameterHandlers = parameterHandlers;
    }

    private ParameterHandler findParameterHandlerForParameter(ParameterInfo param) {
        for (ParameterHandler handler : parameterHandlers) {
            if (handler.support(param)) {
                return handler;
            }
        }
        throw new ContainerException("没有合适的ParameterHandler: " + param.getParameterType());
    }

    public ObjectFactory<?>[] getParamFactories(Executable executable) {
        Class<?>[] parameterTypes = executable.getParameterTypes();
        Type[] genericParameterTypes = executable.getGenericParameterTypes();
        Annotation[][] parameterAnnotations = executable.getParameterAnnotations();
        List<ObjectFactory<?>> params = new ArrayList<>();

        for (int i = 0; i < parameterTypes.length; ++i) {
            AnnotationMetadata annotationMetadata = new AnnotationMetadata(parameterAnnotations[i]);
            ParameterInfo param = new ParameterInfo(parameterTypes[i], genericParameterTypes[i], annotationMetadata);
            ParameterHandler handler = findParameterHandlerForParameter(param);
            params.add(handler.handle(param, container));
        }

        return params.toArray(new ObjectFactory[0]);
    }
}
